
import Method from './collider-methods';
import CONST from '../collision-const';

const ColliderDetection={};

/**
 * 检测两个碰撞体是否相交
 * @param colliderA {Collider}
 * @param colliderB {Collider}
 * @param pointOnA {Vector3}
 * @param pointOnB {Vector3}
 * @returns {boolean|(boolean|*)}
 */
ColliderDetection.checkColliderPair=(colliderA, colliderB,pointOnA,pointOnB)=>{
    if(colliderA.colliderType===CONST.COLLIDER_TYPE||colliderB.colliderType===CONST.COLLIDER_TYPE){
        console.warn('cannot apply detection for a COLLIDER_TYPE object!');
        return false;
    }
    let type=colliderA.colliderType<<colliderB.colliderType;
    switch (type){
        case CONST.COLLIDER_TYPE_BOX<<CONST.COLLIDER_TYPE_BOX:
            return ColliderDetection.boxVsBox(colliderA,colliderB);
        case CONST.COLLIDER_TYPE_SPHERE<<CONST.COLLIDER_TYPE_SPHERE:
            return ColliderDetection.sphereVsSphere(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_BOX<<CONST.COLLIDER_TYPE_SPHERE:
            return ColliderDetection.boxVsSphere(colliderA,colliderB);
        case CONST.COLLIDER_TYPE_SPHERE<<CONST.COLLIDER_TYPE_BOX:
            return ColliderDetection.boxVsSphere(colliderB,colliderA);
        case CONST.COLLIDER_TYPE_CAPSULE<<CONST.COLLIDER_TYPE_CAPSULE:
            return ColliderDetection.capsuleVsCapsule(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_BOX<<CONST.COLLIDER_TYPE_CAPSULE:
            return ColliderDetection.boxVsCapsule(colliderA,colliderB);
        case CONST.COLLIDER_TYPE_CAPSULE<<CONST.COLLIDER_TYPE_BOX:
            return ColliderDetection.boxVsCapsule(colliderB,colliderA);
        case CONST.COLLIDER_TYPE_SPHERE<<CONST.COLLIDER_TYPE_CAPSULE:
            return ColliderDetection.sphereVsCapsule(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_CAPSULE<<CONST.COLLIDER_TYPE_SPHERE:
            return ColliderDetection.sphereVsCapsule(colliderB,colliderA,pointOnB,pointOnA);
        case CONST.COLLIDER_TYPE_BOX_SCREEN<<CONST.COLLIDER_TYPE_BOX_SCREEN:
            return ColliderDetection.boxScreenVsBoxScreen(colliderA,colliderB);
        case CONST.COLLIDER_TYPE_MESH<<CONST.COLLIDER_TYPE_MESH:
            return ColliderDetection.meshVsMesh(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_MESH<<CONST.COLLIDER_TYPE_BOX:
            return ColliderDetection.meshVsBox(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_BOX<<CONST.COLLIDER_TYPE_MESH:
            return ColliderDetection.meshVsBox(colliderB,colliderA,pointOnB,pointOnA);
        case CONST.COLLIDER_TYPE_MESH<<CONST.COLLIDER_TYPE_SPHERE:
            return ColliderDetection.meshVsSphere(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_SPHERE<<CONST.COLLIDER_TYPE_MESH:
            return ColliderDetection.meshVsSphere(colliderB,colliderA,pointOnB,pointOnA);
        case CONST.COLLIDER_TYPE_MESH<<CONST.COLLIDER_TYPE_CAPSULE:
            return ColliderDetection.meshVsCapsule(colliderA,colliderB,pointOnA,pointOnB);
        case CONST.COLLIDER_TYPE_CAPSULE<<CONST.COLLIDER_TYPE_MESH:
            return ColliderDetection.meshVsCapsule(colliderB,colliderA,pointOnB,pointOnA);
        default:
            console.warn('collision between '+colliderA.colliderType+' and '+colliderB.colliderType+' is not supported!');
            return false;
    }
};

/**
 * meshCollider和capsuleCollider是否相交
 * @param mesh
 * @param capsule
 * @param pointOnMesh
 * @param pointOnCapsule
 * @returns {*|boolean}
 */
ColliderDetection.meshVsCapsule=(mesh,capsule,pointOnMesh,pointOnCapsule)=>{
    let sm=mesh.sphere.applyMatrix4(mesh.matrixWorld);
    let sc=capsule.sphere.applyMatrix4(capsule.matrixWorld);
    if(!sm.intersectsSphere(sc))return false;
    if(mesh.isConvex){
        return Method.convex_capsule(mesh,capsule,pointOnMesh,pointOnCapsule);
    }else{
        /**
         * todo:concave vs capsule
         */
        return false;
    }
};

/**
 * meshCollider和sphereCollider是否相交
 * @param mesh
 * @param sphere
 * @param pointOnMesh
 * @param pointOnSphere
 * @returns {boolean|*}
 */
ColliderDetection.meshVsSphere=(mesh,sphere,pointOnMesh,pointOnSphere)=>{
    let sm=mesh.sphere.applyMatrix4(mesh.matrixWorld);
    let ss=sphere.sphere.applyMatrix4(sphere.matrixWorld);
    if(!sm.intersectsSphere(ss))return false;
    if(mesh.isConvex){
        return Method.convex_sphere(mesh,sphere,pointOnMesh,pointOnSphere);
    }else{
        /**
         * todo:concave vs sphere
         */
        return false;
    }
};

/**
 * meshCollider和boxCollider是否相交
 * @param mesh
 * @param box
 * @param pointOnMesh
 * @param pointOnBox
 * @returns {*|boolean|boolean}
 */
ColliderDetection.meshVsBox=(mesh,box,pointOnMesh,pointOnBox)=>{
    let sm=mesh.sphere.applyMatrix4(mesh.matrixWorld);
    let sb=box.sphere.applyMatrix4(box.matrixWorld);
    if(!sm.intersectsSphere(sb))return false;
    if(mesh.isConvex){
        return Method.convex_obb(mesh,box,pointOnMesh,pointOnBox);
    }else{
        /**
         * todo:concave vs box
         */
        return false;
    }
};

/**
 * meshCollider和meshCollider是否相交
 * @param mesh0
 * @param mesh1
 * @param pointOnA
 * @param pointOnB
 * @returns {*|boolean|boolean}
 */
ColliderDetection.meshVsMesh=(mesh0,mesh1,pointOnA,pointOnB)=>{
    let sa=mesh0.sphere.applyMatrix4(mesh0.matrixWorld);
    let sb=mesh1.sphere.applyMatrix4(mesh1.matrixWorld);
    if(!sa.intersectsSphere(sb))return false;
    if(mesh0.isConvex&&mesh1.isConvex){
        return Method.convex_convex(mesh0,mesh1,pointOnA,pointOnB);
    }else{
        /**
         * todo:convex vs concave
         * todo:concave vs concave
         */
        return false;
    }
};

/**
 * boxScreen和boxScreen是否相交
 * @param boxScn0 {BoxScreenCollider}
 * @param boxScn1 {BoxScreenCollider}
 * @returns {boolean|*}
 */
ColliderDetection.boxScreenVsBoxScreen=(boxScn0,boxScn1)=>{
    if(!boxScn0.sphere.intersectsSphere(boxScn1.sphere))return false;
    return Method.boxScn_boxScn(boxScn0,boxScn1);
};

/**
 * box和sphere是否相交
 * @param box {BoxCollider}
 * @param sphere {SphereCollider}
 * @returns {boolean}
 */
ColliderDetection.boxVsSphere=(box, sphere)=>{
    let sb=box.sphere.applyMatrix4(box.matrixWorld);
    let ss=sphere.sphere.applyMatrix4(sphere.matrixWorld);
    if(!sb.intersectsSphere(ss))return false;
    return Method.obb_sphere(box,sphere);
};

/**
 * sphere和capsule是否相交
 * @param sphere {SphereCollider}
 * @param capsule {CapsuleCollider}
 * @param pointOnSphere
 * @param pointOnCapsule
 * @returns {boolean}
 */
ColliderDetection.sphereVsCapsule=(sphere, capsule,pointOnSphere,pointOnCapsule)=>{
    let ss=sphere.sphere.applyMatrix4(sphere.matrixWorld);
    let sc=capsule.sphere.applyMatrix4(capsule.matrixWorld);
    if(!ss.intersectsSphere(sc))return false;
    return Method.sphere_capsule(sphere,capsule,pointOnSphere,pointOnCapsule);
};

/**
 * box和capsule是否相交
 * @param box {BoxCollider}
 * @param capsule {CapsuleCollider}
 * @returns {boolean}
 */
ColliderDetection.boxVsCapsule=(box, capsule)=>{
    let sb=box.sphere.applyMatrix4(box.matrixWorld);
    let cb=capsule.sphere.applyMatrix4(capsule.matrixWorld);
    if(!sb.intersectsSphere(cb))return false;
    return Method.obb_capsule(box,capsule);
};

/**
 * capsule和capsule是否相交
 * @param capsuleA {CapsuleCollider}
 * @param capsuleB {CapsuleCollider}
 * @param pointOnA
 * @param pointOnB
 * @returns {boolean}
 */
ColliderDetection.capsuleVsCapsule=(capsuleA, capsuleB,pointOnA,pointOnB)=>{
    let ca=capsuleA.sphere.applyMatrix4(capsuleA.matrixWorld);
    let cb=capsuleB.sphere.applyMatrix4(capsuleB.matrixWorld);
    if(!ca.intersectsSphere(cb))return false;
    return  Method.capsule_capsule(capsuleA,capsuleB,pointOnA,pointOnB);
};

/**
 * sphere和sphere是否相交
 * @param sphereA {SphereCollider}
 * @param sphereB {SphereCollider}
 * @param pointOnA
 * @param pointOnB
 * @returns {boolean}
 */
ColliderDetection.sphereVsSphere=(sphereA, sphereB,pointOnA,pointOnB)=>{
    let sa=sphereA.sphere.applyMatrix4(sphereA.matrixWorld);
    let sb=sphereB.sphere.applyMatrix4(sphereB.matrixWorld);
    if(!sa.intersectsSphere(sb))return false;
    return  Method.sphere_sphere(sphereA,sphereB,pointOnA,pointOnB);
};

/**
 * box和box是否相交
 * @param boxA {BoxCollider}
 * @param boxB {BoxCollider}
 * @returns {boolean|*}
 */
ColliderDetection.boxVsBox=(boxA, boxB)=>{
    let sa=boxA.sphere.applyMatrix4(boxA.matrixWorld);
    let sb=boxB.sphere.applyMatrix4(boxB.matrixWorld);
    if(!sa.intersectsSphere(sb))return false;
    return Method.obb_obb(boxA,boxB);
};

export default ColliderDetection;

